package com.funteam.funmask;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;

import min3d.Min3d;

import android.database.Cursor;
import android.annotation.SuppressLint;
import android.app.Activity;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;

import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;

import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.MediaColumns;
import android.util.Log;

import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;

import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.Gallery;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

public class FunMaskActivity extends Activity implements OnClickListener {

	private Bitmap mBitmap;

	private PictureCallback mTakePic = null; // for taken picture
	private boolean isFrontCamera; // is opening front camera
	private SurfaceHolder mHolder = null; // for preview camera
	private Camera mCamera = null;
	private Bitmap mBtmLast = null; // for showing the last picture
	private ImageButton mIbAlbum, mIbShutter = null;

	private int IPosition;

	private int[] mask_list = new int[] {
			// on gallery sample front masks, it's 25 masks below
			R.drawable.mask_tiger_1, R.drawable.mask_tiger_2,
			R.drawable.mask_tiger_3, R.drawable.mask_tiger_4,
			R.drawable.mask_tiger_5,

			R.drawable.mask_rabbit_1, R.drawable.mask_rabbit_2,
			R.drawable.mask_rabbit_3, R.drawable.mask_rabbit_4,
			R.drawable.mask_rabbit_5,

			R.drawable.mask_girl_1, R.drawable.mask_girl_2,
			R.drawable.mask_girl_3, R.drawable.mask_girl_4,
			R.drawable.mask_girl_5,

			R.drawable.mask_boy_1, R.drawable.mask_boy_2,
			R.drawable.mask_boy_3, R.drawable.mask_boy_4,
			R.drawable.mask_boy_5,

			R.drawable.mask_egg_1, R.drawable.mask_egg_2,
			R.drawable.mask_egg_3, R.drawable.mask_egg_4, R.drawable.mask_egg_5 };

	// it's for sample front masks' position when mask is selected
	private static final String CURRENT_POSITION = "current_position";
	private int mCurrentPosition = 0;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fun_mask);

		final CameraSurfaceView cameraView = new CameraSurfaceView(getApplicationContext());
		final FrameLayout previewFrame = (FrameLayout) findViewById(R.id.fl_previewFrame);
		previewFrame.addView(cameraView);

		final DrawOnTop mDraw = new DrawOnTop(this);

		final ImageView ivPreview = (ImageView) findViewById(R.id.iv_preview);

		// Shutter button function definition_ when the button is put, call
		mIbShutter = (ImageButton) this.findViewById(R.id.ib_shutter);

		mIbShutter.setOnClickListener(this);
		mIbShutter.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				cameraView.capture(mTakePic);
			}
		});

		// Album button function definition
		mIbAlbum = (ImageButton) findViewById(R.id.ib_lastpic);
		String[] filePathColumn = { MediaColumns.DATA };

		// Bring the latest picture from FUNMASK folder
		Cursor cursor = null;
		try {
			cursor = getContentResolver().query(
					Images.Media.EXTERNAL_CONTENT_URI, filePathColumn,
					"bucket_display_name='FUNMASK'", null, null);
			cursor.moveToLast();
			int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
			String filePath = cursor.getString(columnIndex); // file path of
																// selected
																// image
			cursor.close();
			// using option for resizing bitmap
			BitmapFactory.Options option1 = new BitmapFactory.Options();
		
			option1.inSampleSize = 34; // making bitmap to 1/34 from original bitmap size
			option1.inPurgeable = true;
			option1.inDither = true;
			// save bitmap which bring the latest picture in FUNMASK folder and resizing 
			mBtmLast = BitmapFactory.decodeFile(filePath, option1);
			
			mIbAlbum.setImageBitmap(mBtmLast);
			
		} catch (Exception e) {
			Log.e("Album Image", "Failed to insert image.", e);
		}

		mIbAlbum.setOnClickListener(this);

		// Front camera button function definition
		ImageButton FrontcameraBtn = (ImageButton) findViewById(R.id.ib_frontcamera);
		FrontcameraBtn.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {

				cameraView.changeCamera();
			}

		});

		// when picture is taken
		mTakePic = new Camera.PictureCallback() {

			public void onPictureTaken(byte[] data, Camera camera) {

				try {

					String path = Environment.getExternalStorageDirectory()
							.toString() + "/FUNMASK/fun" + nowdate() + ".jpg";

					Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
							data.length);

					FileOutputStream fos;

					// front camera taken
					if (isFrontCamera) {

						Matrix matrix = new Matrix();
						matrix.postRotate(90);	// rotate bitmap
						matrix.preScale(-1.0f, 1.0f);	// exchange right and left
						bitmap = Bitmap.createBitmap(bitmap, 0, 0,
								bitmap.getWidth(), bitmap.getHeight(), matrix,
								false);

					} else { // back camera taken

						try {

							Matrix matrix = new Matrix();
							matrix.postRotate(90);
							bitmap = Bitmap.createBitmap(bitmap, 0, 0,
									bitmap.getWidth(), bitmap.getHeight(),
									matrix, false);

						} catch (OutOfMemoryError ex) {

						}

					}

					ivPreview.setImageBitmap(bitmap);
					previewFrame.removeAllViews();
					previewFrame.addView(ivPreview);
					previewFrame.addView(mDraw);

					// capture all screen even with UI
					View v1 = previewFrame.getRootView();
					v1.setDrawingCacheEnabled(true);
					bitmap = v1.getDrawingCache();

					// crop image
					bitmap = Bitmap.createBitmap(bitmap);
//					bitmap = Bitmap.createBitmap(bitmap, 0, 120, 800, 1030); //Galaxy Note
					//bitmap = Bitmap.createBitmap(bitmap, 0, 90, 480, 620); // Galaxy
																			// S2,
																			// S2
																			// LTE
					// restart preview
					previewFrame.addView(cameraView);

					try {
						fos = new FileOutputStream(path);

						// change bitmap to jpg
						bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);

					} catch (FileNotFoundException e) {
						e.printStackTrace();
						Log.d("Camera", e.getMessage());
					}  catch (OutOfMemoryError e) {
						// TODO Auto-generated catch block
						Log.d("Camera", e.getMessage());
					}

					// for saving bitmap
					File savedFile = new File(path);

					ContentValues values = new ContentValues();
					values.put(Images.Media.DATA, savedFile.getAbsolutePath());
					values.put(Images.Media.TITLE, savedFile.getName());
					values.put(Images.Media.DISPLAY_NAME, savedFile.getName());
					values.put(Images.Media.BUCKET_ID, savedFile.getName());
					values.put(Images.Media.DESCRIPTION, savedFile.getName());

					FileNameMap fileNameMap = URLConnection.getFileNameMap();
					values.put(Images.Media.MIME_TYPE,
							fileNameMap.getContentTypeFor(path));

					FunMaskActivity.this.getContentResolver().insert(
							Images.Media.EXTERNAL_CONTENT_URI, values);

					Toast.makeText(getApplicationContext(),
							"Photo is saved in the album.", Toast.LENGTH_LONG)
							.show();

					Log.i(Min3d.TAG, "save ok");
					
					// get and set picture to album preview
					// Album preview auto refresh
					String[] filePathColumn = { MediaColumns.DATA };

					Cursor cursor = null;

					try {
						cursor = getContentResolver().query(
								Images.Media.EXTERNAL_CONTENT_URI,
								filePathColumn,
								"bucket_display_name='FUNMASK'", null, null);

						if (cursor == null) {
							mIbAlbum.setId(R.drawable.ic_launcher);
						} else {

							cursor.moveToFirst();
							int columnIndex = cursor
									.getColumnIndex(filePathColumn[0]);
							String filePath = cursor.getString(columnIndex); // file
																				// path
																				// of
																				// selected
																				// image
							cursor.close();

							BitmapFactory.Options option1 = new BitmapFactory.Options();
							
							option1.inSampleSize = 34;
							option1.inPurgeable = true;
							option1.inDither = true;
							
							mBtmLast = BitmapFactory.decodeFile(filePath, option1);
							
							mIbAlbum.setImageBitmap(mBtmLast);
							
						}
					} catch (OutOfMemoryError ex) {
						
					}

					bitmap.recycle();

					// restart
					camera.startPreview();
				} catch (Exception e) {
					Log.e("SampleCapture", "Failed to insert image.", e);
				}
			}
		};

		// sample front mask list
		Gallery BasicMask_gallery = (Gallery) findViewById(R.id.gl_mask_gallery);

		// declare the gallery view
		// use the position and list item of sample front mask array
		BasicMask_gallery.setAdapter(new ImageAdapter(this));

		BasicMask_gallery.setOnItemClickListener(new OnItemClickListener() {

			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {

				IPosition = position;

				previewFrame.removeAllViews();
				previewFrame.addView(cameraView);
				previewFrame.addView(mDraw);

			}

		});

	}// OnCreate
	
	// go to albumactivity and when the new picture is taken, refresh
	public void gotoFunMaskAlbum() {
		
		// for recognizing that there is picture in FUNMASK folder or not
		String[] filePathColumn = { MediaColumns.DATA };

		Cursor cursor = null;

		cursor = getContentResolver().query(
				Images.Media.EXTERNAL_CONTENT_URI, filePathColumn,
				"bucket_display_name='FUNMASK'", null, null);

		
		if (cursor.getCount() == 0) {
			Toast.makeText(getApplicationContext(),
					"There is no picture in gallery.",
					Toast.LENGTH_SHORT).show();
		} else {
			Intent intent = new Intent(FunMaskActivity.this,
					AlbumActivity.class);
			startActivity(intent);
		}
	}

	// use imageadapter-> it's for return sample front mask values return
	public class ImageAdapter extends BaseAdapter {
		int mGalleryItemBackground;
		private Context mContext;

		public ImageAdapter(Context c) {
			mContext = c;

		}

		public int getCount() {
			return mask_list.length;
		}

		public Object getItem(int position) {
			return position;
		}

		public long getItemId(int position) {
			return position;
		}

		public View getView(int position, View convertView, ViewGroup parent) {
			ImageView i = new ImageView(mContext);

			i.setImageResource(mask_list[position]);
			i.setLayoutParams(new Gallery.LayoutParams(200, 120));
//			i.setLayoutParams(new Gallery.LayoutParams(150,100)); //Galaxy Note
			//i.setLayoutParams(new Gallery.LayoutParams(120, 80)); // Galaxy S2,
																	// S2 LTE
			i.setScaleType(ImageView.ScaleType.FIT_CENTER);
			i.setBackgroundColor(mGalleryItemBackground);
			return i;
		}

	}

	// picture's taken date and time for declare the picture name
	// it's use java util
	public String nowdate() {
		java.util.Date date = new java.util.Date();
		String year = String.valueOf(date.getYear() + 1900);
		String month = int2code(date.getMonth() + 1);
		String day = int2code(date.getDate());
		String hour = int2code(date.getHours());
		String minute = int2code(date.getMinutes());
		String second = int2code(date.getSeconds());
		return year + month + day + hour + minute + second;
	}

	// declare the number type for date
	public String int2code(int val) {
		String str = "";
		if (val < 10) {
			str += String.valueOf("0" + val);
		} else {
			str += String.valueOf(val);
		}
		return str;
	}

	// preview's Surfaceview Class Definition
	/*
	 * Camera SurfaceView
	 */
	// Control SurfaceView's Surface object using Surfaceholder.Callback
	@SuppressLint("NewApi")
	private class CameraSurfaceView extends SurfaceView implements
			SurfaceHolder.Callback {

		public CameraSurfaceView(Context context) {
			super(context);

			mHolder = getHolder();
			mHolder.addCallback(this);
			mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}

		public void surfaceCreated(SurfaceHolder holder) {

			try {
				mCamera = Camera.open();
				mCamera.setDisplayOrientation(90);
				mCamera.setPreviewDisplay(holder);

				Camera.Parameters p = mCamera.getParameters();
				p.set("camera_id", 2);
				mCamera.setParameters(p);

			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		ShutterCallback shutter = new ShutterCallback() {

			public void onShutter() {
				// No action to be performed on the Shutter callback.
			}
		};


		PictureCallback raw = new PictureCallback() {

			public void onPictureTaken(byte[] data, Camera camera) {
				// No action taken on the raw data. Only action taken on jpeg
				// data.
			}
		};

		// ///////////////////////////// front camera start /////////////////////////////
		public Camera openCamera(int facing) {

			int cameraCount = -1;
			Camera cam = null;
			Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
			cameraCount = Camera.getNumberOfCameras();

			for (int cameraId = 0; cameraId < cameraCount; cameraId++) {

				Camera.getCameraInfo(cameraId, cameraInfo);

				if (cameraInfo.facing == facing) {

					try {
						cam = Camera.open(cameraId);
						break;
					} catch (RuntimeException e) {
						e.printStackTrace();
					}
				}
			}
			return cam;
		}

		public void startCamera(int facing) {

			mCamera = openCamera(facing);
			mCamera.setDisplayOrientation(90);

			if (mCamera == null) {

				mCamera = Camera.open();
				isFrontCamera = false;

			}

			try {

				mCamera.setPreviewDisplay(mHolder);

			} catch (IOException e) {
				Log.e("CameraSurfaceView", "Failed to set camera preview.", e);
			}
		}

		public void closeCamera() {

			if (mCamera != null) {

				mCamera.stopPreview();
				mCamera.setPreviewCallback(null);
				mCamera.release();
				mCamera = null;
			}
		}

		// exchange front camera and back camera
		public void changeCamera() {

			closeCamera();
			isFrontCamera = !isFrontCamera;

			if (isFrontCamera) {
				startCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);

			} else {
				startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
			}
			mCamera.startPreview();

		}

		// ///////////////////////////// front camera finish /////////////////////////////
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			Camera.Parameters parameters = mCamera.getParameters();
			// Bring all devices' supported screen size and select the biggest size
			// Setup preview size
			mCamera.setParameters(parameters);
			// Draw preview on surfaceview
			mCamera.startPreview();
		}

		public void surfaceDestroyed(SurfaceHolder holder) {
			mCamera.stopPreview();
			mCamera.release();
			mCamera = null;
		}

		// capture surfaceview
		public boolean capture(final Camera.PictureCallback handler)
				throws OutOfMemoryError {

			if (mCamera != null) {
				mCamera.startPreview();
				mCamera.autoFocus(null);
				mCamera.takePicture(shutter, raw, handler);

				return true;
			} else {
				return false;
			}

		}

	}

	
	// 2D Mask
	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (outState == null) {
			return;
		}
		outState.putInt(CURRENT_POSITION, mCurrentPosition);
	}

	// 2D Mask scale, position
	@SuppressLint("NewApi")
	public class DrawOnTop extends View {
		private float MIN_ZOOM = 0.5f;
		private float MAX_ZOOM = 3f;

		private float scaleFactor = 1.f;

		private ScaleGestureDetector detector;

		private float mPosX;
		private float mPosY;

		private float mLastTouchX;
		private float mLastTouchY;

		private static final int INVALID_POINTER_ID = -1;
		private int mActivePointerid = INVALID_POINTER_ID;

		public DrawOnTop(Context context) {
			super(context);
			detector = new ScaleGestureDetector(getContext(),
					new ScaleListener());

		}

		// draw 2D Mask
		protected void onDraw(Canvas canvas) {

			Paint paint = new Paint();

			switch (IPosition) {
			case 0:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_tiger1);
				break;
			case 1:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_tiger2);
				break;
			case 2:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_tiger3);
				break;
			case 3:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_tiger4);
				break;
			case 4:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_tiger5);
				break;
			case 5:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_rabbit1);
				break;
			case 6:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_rabbit2);
				break;
			case 7:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_rabbit3);
				break;
			case 8:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_rabbit4);
				break;
			case 9:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_rabbit5);
				break;
			case 10:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_woman1);
				break;
			case 11:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_woman2);
				break;
			case 12:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_woman3);
				break;
			case 13:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_woman4);
				break;
			case 14:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_woman5);
				break;
			case 15:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_man1);
				break;
			case 16:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_man2);
				break;
			case 17:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_man3);
				break;
			case 18:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_man4);
				break;
			case 19:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_man5);
				break;
			case 20:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_egg1);
				break;
			case 21:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_egg2);
				break;
			case 22:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_egg3);
				break;
			case 23:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_egg4);
				break;
			case 24:
				mBitmap = BitmapFactory.decodeResource(getResources(),
						R.drawable.img_egg5);
				break;
			}

			canvas.drawColor(Color.TRANSPARENT);
			canvas.translate(mPosX, mPosY);
			canvas.scale(scaleFactor, scaleFactor);
			canvas.drawBitmap(mBitmap, 0, 0, paint);

			super.onDraw(canvas);
		}

		private class ScaleListener extends
				ScaleGestureDetector.SimpleOnScaleGestureListener {

			@Override
			public boolean onScale(ScaleGestureDetector detector) {

				scaleFactor *= detector.getScaleFactor();

				scaleFactor = Math.max(MIN_ZOOM,
						Math.min(scaleFactor, MAX_ZOOM));

				invalidate();

				return true;

			}

		}

		// 2D Mask TouchEvent
		@Override
		public boolean onTouchEvent(MotionEvent ev) {

			final int action = ev.getAction();

			switch (action) {
			case MotionEvent.ACTION_DOWN: // when screen touched
			{
				final float x = ev.getX(); // present coordinates
				final float y = ev.getY();

				mLastTouchX = x;
				mLastTouchY = y;

				mActivePointerid = ev.getPointerId(0);
				break;
			}

			case MotionEvent.ACTION_MOVE: // moving image when image touched
			{
				final float x = ev.getX(); // present coordinates
				final float y = ev.getY();

				final float dx = x - mLastTouchX;
				final float dy = y - mLastTouchY;

				mPosX += dx;
				mPosY += dy;

				mLastTouchX = x;
				mLastTouchY = y;

				invalidate();

				break;
			}

			case MotionEvent.ACTION_UP: // untouched screen
			{
				mActivePointerid = INVALID_POINTER_ID;
				break;
			}

			case MotionEvent.ACTION_CANCEL: {
				mActivePointerid = INVALID_POINTER_ID;
				break;
			}

			case MotionEvent.ACTION_POINTER_UP: // untouched screen
			{
				final int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK);
				final int pointerId = ev.getPointerId(pointerIndex); // pointer ID

				if (pointerId == mActivePointerid) {
					final int newPointerIndex = pointerIndex == 0 ? 1 : 0;

					mLastTouchX = ev.getX(newPointerIndex);
					mLastTouchY = ev.getY(newPointerIndex);
					mActivePointerid = ev.getPointerId(newPointerIndex);
				}
				break;
			}

			}
			detector.onTouchEvent(ev);
			return true;
		}
	}

	@Override
	public void onClick(View v) {
		switch(v.getId()) {
		case R.id.ib_lastpic:
			gotoFunMaskAlbum();
			break;
		}
	}
}
